package controller;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.swing.SwingUtilities;

import Chat.ChatClient;
import listeners.BuyListener;
import listeners.ChatListener;
import listeners.LoginListener;
import model.ModelShop;
import model.MyTableModel;
import model.Order;
import model.Product;
import netzwerk.IncomingCustomer;
import netzwerk.OutgoingCustomer;
import view.ViewCustomer;

public class ControllerCustomer implements BuyListener, LoginListener, ChatListener {

	private ModelShop modelShop;
	private ViewCustomer viewCustomer;
	private CopyOnWriteArrayList<Order> orders = new CopyOnWriteArrayList<>();
	private CopyOnWriteArrayList<Order> ordersFromServer = new CopyOnWriteArrayList<>();
	private Socket serverCon;
	private MyTableModel tableModel;
	private Order order;
	OutgoingCustomer outgoingCustomer = null;
	Thread incomingCustomer = null;

	ObjectInputStream in = null;
	ObjectOutputStream out = null;

	public ControllerCustomer() {

		//Object-Streams erzeugen
		try {
			serverCon = new Socket(InetAddress.getLocalHost(), 6666);
			in = new ObjectInputStream(serverCon.getInputStream());
			out = new ObjectOutputStream(serverCon.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	
	public void link(ModelShop model, ViewCustomer view) {

		// Model anmelden
		this.modelShop = model;
		this.modelShop.addObserver(view);

		// Listener hinzufügen
		this.viewCustomer = view;
		viewCustomer.addBuyListener(this);
		viewCustomer.addChatListener(this);

		// View aktualisieren
		viewCustomer.update(modelShop, null);

		tableModel = new MyTableModel(modelShop);
		modelShop.addObserver(new Observer() {

			@Override
			public void update(Observable o, Object arg) {
				tableModel.fireTableDataChanged();
			}
		});

		viewCustomer.getProductTable().setModel(tableModel);

		viewCustomer.startTimer();

	}

	
	// Wird nach dem Klicken des Buy-Buttons aufgerufen
	// Fügt die aktuelle Bestellung der Bestellliste hinzu; Wenn return true ist, wird Login-Fenster geöffnet
	@Override
	public boolean buy() {

		order = new Order();
		for (int r = 0; r < tableModel.getRowCount(); r++) {

			if ((int) tableModel.getValueAt(r, 3) > 0) {
				String prodName = (String) tableModel.getValueAt(r, 0);
				Product selProd = new Product();
				Product orderedProd = new Product();
				selProd = (Product) modelShop.findProductByName(prodName);
				orderedProd.setName(selProd.getName());
				orderedProd.setPrice(selProd.getPrice());
				int q = Integer.parseInt(tableModel.getValueAt(r, 3).toString());
				if (q > selProd.getQuantity()) {
					System.out.println("Maximale Bestellmenge für " + selProd.getName()
							+ " überschritten");
					System.out.println("Das Produkt wurde der Bestellung daher nicht hinzugefügt.");
					continue;
				} else {
					orderedProd.setQuantity(q);
				}
				try {
					order.add(orderedProd);
				} catch (Exception e1) {
					System.out
							.println("Das Produkt konnte der Bestellung nicht hinzugefügt werden.");
					e1.printStackTrace();
				}
			}
		}
		if (order.isEmpty()) {
			System.out
					.println("Bitte geben Sie eine Bestellmenge größer 0 an und berücksichtigen Sie die verfügbare Menge.");
			return false;
		}

		viewCustomer.addLoginListener(this);
		return true;

	}

	
	// Wird beim Bestätigen des Login-Dialogs aufgerufen
	@Override
	public void login(String name, String password) {

		System.out.println("Controller erstellt OutgoingCustomer und verschickt Order");
		if (outgoingCustomer == null) {
			outgoingCustomer = new OutgoingCustomer(out, name, password, orders);
			outgoingCustomer.start();
		}
		if (incomingCustomer == null) {
			// Ergebnis (Order und Login-Feedback) entgegennehmen
			incomingCustomer = new IncomingCustomer(in, this);
			incomingCustomer.start();
		}

		outgoingCustomer.setLoginData(name, password);

		try {
			synchronized (orders) {
				orders.add(order);
				orders.notify();
			}

		} catch (Exception e1) {
			System.out
					.println("Die Bestellung konnte der Bestellhistorie nicht hinzugefügt werden.");
			e1.printStackTrace();
		}

	}
	

	public void guiUpdate(final Order order) {
		
		ordersFromServer.add(order);

		try {
			// Dann in der GUI ausgeben
			final Order[] orderArray = ordersFromServer.toArray(new Order[0]);
			SwingUtilities.invokeAndWait(new Runnable() {

				@Override
				public void run() {
					viewCustomer.orderList.setListData(orderArray);

					// OrderCount nach Bestellung auf 0 setzen
					for (int row = 0; row < tableModel.getRowCount(); row++) {
						tableModel.setValueAt(0, row, 3);
					}
				}

			});

		} catch (Exception e) {
			e.printStackTrace();
		}

		// ModelShop aktualisieren -> MaxCount bzw. Quantity verringern
		for (fpt.com.Product p : order) {
			Product modelShopProd = (Product) modelShop.findProductByName(p.getName());
			(modelShopProd).setQuantity(modelShopProd.getQuantity() - p.getQuantity());
		}

	}
	

	@Override
	public void openChat(final String username) {

		System.out.println("Öffne Chat als \"" + username + "\"");
		Thread t = new Thread() {
			public void run() {
				try {
					new ChatClient(username);
				} catch (RemoteException e) {
					System.err.println("Chat konnte nicht aufgerufen werden.");
					e.printStackTrace();
				} catch (AlreadyBoundException e) {
					System.out.println("Name bereits vorhanden. Bitte anderen Namen wählen.");
					viewCustomer.setNameVorhanden(true);
					viewCustomer.getButtonChat().doClick();
				}

			}
		};
		t.start();

	}

}
